//! Build script for generating Rust code from OpenTelemetry protobuf definitions.
//!
//! This build script:
//! 1. Discovers all .proto files in the proto directory
//! 2. Compiles them using tonic-prost-build
//! 3. Renames generated files to a flattened naming scheme
//! 4. Generates a mod.rs file with proper module structure

use std::fs;
use std::path::PathBuf;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let out_dir = PathBuf::from("src/internal/data/protogen");
    fs::create_dir_all(&out_dir)?;

    let mut proto_files = Vec::new();
    find_proto_files("proto/opentelemetry/proto", &mut proto_files)?;

    if proto_files.is_empty() {
        eprintln!("No .proto files found");
        return Ok(());
    }

    // Generate Rust code from protobuf definitions
    tonic_prost_build::configure()
        .out_dir(&out_dir)
        .protoc_arg("--experimental_allow_proto3_optional")
        .compile_protos(&proto_files, &["proto".to_string()])?;

    // Rename generated files to flattened naming scheme
    let file_mapping = [
        ("opentelemetry.proto.common.v1.rs", "common_v1.rs"),
        ("opentelemetry.proto.logs.v1.rs", "logs_v1.rs"),
        ("opentelemetry.proto.metrics.v1.rs", "metrics_v1.rs"),
        ("opentelemetry.proto.resource.v1.rs", "resource_v1.rs"),
        ("opentelemetry.proto.trace.v1.rs", "trace_v1.rs"),
        ("opentelemetry.proto.profiles.v1development.rs", "profiles_v1development.rs"),
        ("opentelemetry.proto.collector.logs.v1.rs", "collector_logs_v1.rs"),
        ("opentelemetry.proto.collector.metrics.v1.rs", "collector_metrics_v1.rs"),
        ("opentelemetry.proto.collector.trace.v1.rs", "collector_trace_v1.rs"),
        ("opentelemetry.proto.collector.profiles.v1development.rs", "collector_profiles_v1development.rs"),
    ];

    for (old, new) in &file_mapping {
        let old_path = out_dir.join(old);
        let new_path = out_dir.join(new);
        if old_path.exists() {
            fs::rename(old_path, new_path)?;
        }
    }

    // Generate mod.rs with nested module definitions
    generate_mod_rs(&out_dir)?;

    println!("cargo:rerun-if-changed=proto/");
    Ok(())
}

/// Recursively find all .proto files in the given directory.
fn find_proto_files(dir: &str, files: &mut Vec<String>) -> Result<(), Box<dyn std::error::Error>> {
    for entry in fs::read_dir(dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_dir() {
            find_proto_files(path.to_str().unwrap(), files)?;
        } else if path.extension().and_then(|s| s.to_str()) == Some("proto") {
            files.push(path.to_str().unwrap().to_string());
        }
    }
    Ok(())
}

/// Generate the mod.rs file with proper module structure for the protobuf types.
fn generate_mod_rs(out_dir: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
    let content = r#"//! Generated protobuf modules for OpenTelemetry Protocol (OTLP).
//!
//! This module contains all the generated Rust code from OpenTelemetry protobuf definitions,
//! organized by telemetry type and API version.

/// Common data structures shared across all telemetry types.
pub mod common {
    pub mod v1 {
        include!("common_v1.rs");
    }
}

/// Log data structures for OpenTelemetry logging.
pub mod logs {
    pub mod v1 {
        include!("logs_v1.rs");
    }
}

/// Metrics data structures for OpenTelemetry metrics.
pub mod metrics {
    pub mod v1 {
        include!("metrics_v1.rs");
    }
}

/// Resource identification and attributes.
pub mod resource {
    pub mod v1 {
        include!("resource_v1.rs");
    }
}

/// Distributed tracing data structures.
pub mod trace {
    pub mod v1 {
        include!("trace_v1.rs");
    }
}

/// Profiling data structures (experimental).
pub mod profiles {
    pub mod v1development {
        include!("profiles_v1development.rs");
    }
}

/// OTLP service definitions for collectors.
pub mod collector {
    pub mod logs {
        pub mod v1 {
            include!("collector_logs_v1.rs");
        }
    }

    pub mod metrics {
        pub mod v1 {
            include!("collector_metrics_v1.rs");
        }
    }

    pub mod trace {
        pub mod v1 {
            include!("collector_trace_v1.rs");
        }
    }

    pub mod profiles {
        pub mod v1development {
            include!("collector_profiles_v1development.rs");
        }
    }
}
"#
    .trim();

    fs::write(out_dir.join("mod.rs"), content)?;
    Ok(())
}